home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / POP2SERV.C < prev    next >
C/C++ Source or Header  |  1997-09-07  |  20KB  |  872 lines

  1. /* POP2 Server state machine - see RFC 937
  2.  *
  3.  *  also see other credits in popcli.c
  4.  *  10/89 Mike Stockett wa7dyx
  5.  *  Modified 5/27/90 by Allen Gwinn, N5CKP, for later NOS releases.
  6.  *  Added to NOS by PA0GRI 2/6/90 (and linted into "standard" C)
  7.  *
  8.  *    Aug-Oct 92    Mike Bilow, N1BEE, mikebw@ids.net
  9.  *        Extensive bug fixes, changed uses of Borland stat()
  10.  *        to fsize() in order to fix intermittent crashes
  11.  *
  12.  *    November 93    KO4KS/Brian A. Lantz
  13.  *        Modified close_folder() for TNOS control files
  14.  *
  15.  */
  16.  
  17. #include "global.h"
  18. #ifdef POP2SERVER
  19. #include <time.h>
  20. #ifndef MSDOS
  21. #include <sys/stat.h>
  22. #endif
  23. #include "mbuf.h"
  24. #include "socket.h"
  25. #include "smtp.h"
  26. #include "mailbox.h"
  27. #include "bm.h"
  28. #include "stats.h"
  29.  
  30. #if !defined(_lint)
  31. static char rcsid[] OPTIONAL = "$Id: pop2serv.c,v 1.19 1997/09/07 21:18:28 root Exp root $";
  32. #endif
  33.  
  34.  
  35. #undef DEBUG                /* N1BEE */
  36.  
  37.  
  38. /* ---------------- common server data structures ---------------- */
  39.  
  40. /* POP server control block */
  41.  
  42. struct pop_scb {
  43.     int    socket;     /* socket number for this connection */
  44.     char    state;        /* server state */
  45. #define     LSTN    0
  46. #define     AUTH    1
  47. #define     MBOX    2
  48. #define     ITEM    3
  49. #define     NEXT    4
  50. #define     DONE    5
  51.     char    buf[TLINELEN+1];    /* input line buffer */
  52.     char    count;        /* line buffer length */
  53.     char    username[32];    /* user/folder name */
  54.     FILE    *wf;        /* work folder file pointer */
  55.     int    folder_len;    /* number of msgs in current folder */
  56.     int    msg_num;    /* current msg number */
  57.     long    msg_len;    /* length of current msg */
  58.     int    msg_status_size; /* size of the message status array */
  59.     long    curpos;     /* current msg's position in file */
  60.     long    folder_file_size; /* length of the current folder file, in bytes */
  61.     long    nextpos;    /* next msg's position in file */
  62.     char    folder_modified; /* mail folder contents modified flag */
  63.     int16    *msg_status;    /* message status array pointer */
  64. };
  65.  
  66. #define NULLSCB     (struct pop_scb *)0
  67.  
  68. /* Response messages */
  69.  
  70. static char    count_rsp[]    = "#%d messages in this folder\n",
  71.         error_rsp[]    = "- ERROR: %s\n",
  72.         greeting_msg[] = "+ POP2 %s\n",
  73. /*        length_rsp[]   = "=%ld bytes in this message\n", */
  74.         length_rsp[]   = "=%ld characters in Message #%d\n",
  75.         msg_line[]     = "%s\n",
  76.         no_mail_rsp[]  = "+ No mail, sorry\n",
  77.         no_more_rsp[]  = "=%d No more messages in this folder\n",
  78.         signoff_msg[]  = "+ Bye, thanks for calling\n";
  79.  
  80. static struct pop_scb *create_scb (void);
  81. static void delete_scb (struct pop_scb *scb);
  82. static void popserv (int s,void *unused,void *p);
  83. static int poplogin (char *pass,char *username);
  84. void state_error (struct pop_scb *,const char *);
  85. void open_folder (struct pop_scb *);
  86. void do_cleanup (struct pop_scb *);
  87. void read_message (struct pop_scb *);
  88. void retrieve_message (struct pop_scb *);
  89. void deletemsg (struct pop_scb *,int);
  90. void get_message (struct pop_scb *,int);
  91. void print_message_length (struct pop_scb *);
  92. void close_folder (struct pop_scb *);
  93. #ifdef POP_FOLDERS
  94. void select_folder (struct pop_scb *);
  95. #endif
  96.  
  97. static void pop_sm (struct pop_scb *scb);
  98.  
  99. static int Spop = -1; /* prototype socket for service */
  100.  
  101.  
  102.  
  103. /* Start up POP receiver service */
  104. int
  105. pop2start (int argc, char **argv, void *p)
  106. {
  107.     return (installserver (argc, argv, &Spop, "POP2 listener", IPPORT_POP2,
  108.         INADDR_ANY, "POP2 server", popserv, 4096, NULL));
  109. }
  110.  
  111.  
  112.  
  113. /* Shutdown POP2 service (existing connections are allowed to finish) */
  114.  
  115. int
  116. pop2stop (int argc, char **argv, void *p)
  117. {
  118.     return (deleteserver (&Spop));
  119. }
  120.  
  121.  
  122.  
  123. static void
  124. popserv(s,unused,p)
  125. int s;
  126. void *unused;
  127. void *p;
  128. {
  129. struct pop_scb *scb;
  130.  
  131.     sockowner(s,Curproc);        /* We own it now */
  132.     log(s,"open POP2");
  133.  
  134.     if((scb = create_scb()) == NULLSCB) {
  135.         tputs(Nospace);
  136.         log(s,"close POP2 - no space");
  137.         close_s(s);
  138.         return;
  139.     }
  140.  
  141. #ifdef STATS_USE
  142.     STATS_adduse (1);
  143.     MiscUsers++;
  144. #endif
  145.     scb->socket = s;
  146.     scb->state  = AUTH;
  147.  
  148.     usprintf(s,greeting_msg,Hostname);
  149.  
  150. loop:    if ((scb->count = recvline(s,scb->buf,TLINELEN)) == -1){
  151.         /* He closed on us */
  152.  
  153.         goto quit;
  154.     }
  155.  
  156.     rip(scb->buf);
  157.     if (strlen(scb->buf) == 0)    /* Ignore blank cmd lines */
  158.         goto loop;
  159.  
  160. #ifdef DEBUG
  161.     if(Mailtrace >= 3) {
  162.         tcmdprintf("POP2SERV(popserv): Processing line <%s>\n",scb->buf);
  163.         /* getch(); */
  164.     }
  165. #endif /* DEBUG */
  166.  
  167.     /* Convert lower, and mixed case commands to UPPER case - Ashok */
  168.     for(cp = scb->buf;*cp != ' ' && *cp != '\0';cp++)
  169.         *cp = toupper(*cp);
  170.  
  171.     pop_sm(scb);
  172.     if (scb->state == DONE)
  173.         goto quit;
  174.  
  175.     goto loop;
  176.  
  177. quit:
  178. #ifdef STATS_USE
  179.     MiscUsers--;
  180. #endif
  181.     log(scb->socket,"close POP2");
  182.     close_s(scb->socket);
  183.     delete_scb(scb);
  184. }
  185.  
  186.  
  187.  
  188. /* Create control block, initialize */
  189.  
  190. static struct
  191. pop_scb *create_scb()
  192. {
  193. register struct pop_scb *scb;
  194.  
  195.     if((scb = (struct pop_scb *)callocw(1,sizeof (struct pop_scb))) == NULLSCB)
  196.         return NULLSCB;
  197.  
  198.     scb->username[0] = '\0';
  199.     scb->msg_status = NULL;
  200.     scb->wf = NULL;
  201.  
  202.     scb->count = scb->folder_file_size = scb->msg_num = 0;
  203.  
  204.     scb->folder_modified = FALSE;
  205.     return scb;
  206. }
  207.  
  208.  
  209.  
  210. /* Free resources, delete control block */
  211.  
  212. static void
  213. delete_scb(scb)
  214. register struct pop_scb *scb;
  215. {
  216.     if (scb == NULLSCB)
  217.         return;
  218.     if (scb->wf != NULL)
  219.         fclose(scb->wf);
  220.     if (scb->msg_status  != NULL)
  221.         free((char *)scb->msg_status);
  222.  
  223.     free((char *)scb);
  224. }
  225.  
  226.  
  227.  
  228. /* --------------------- start of POP server code ------------------------ */
  229.  
  230. #define BITS_PER_WORD    16
  231.  
  232. #define isSOM(x)    ((strncmp(x,"From ",5) == 0))    /* Start Of Message */
  233.  
  234. /* Command string specifications */
  235.  
  236. static char    ackd_cmd[] = "ACKD",
  237.         acks_cmd[] = "ACKS",
  238. #ifdef POP_FOLDERS
  239.         fold_cmd[] = "FOLD ",
  240. #endif
  241.         login_cmd[] = "HELO ",
  242.         nack_cmd[] = "NACK",
  243.         quit_cmd[] = "QUIT",
  244.         read_cmd[] = "READ",
  245.         retr_cmd[] = "RETR";
  246.  
  247.  
  248.         
  249. static void
  250. pop_sm(scb)
  251. struct pop_scb *scb;
  252. {
  253. char password[30];
  254.  
  255.     if (scb == NULLSCB)    /* be certain it is good -- wa6smn */
  256.         return;
  257.  
  258.     switch(scb->state) {
  259.     case AUTH:
  260. #ifdef DEBUG
  261.         if(Mailtrace >= 3)
  262.             tcmdprintf("POP2SERV(pop_sm): Entering case AUTH\n");
  263. #endif /* DEBUG */
  264.         if (strncmp(scb->buf,login_cmd,strlen(login_cmd)) == 0){
  265.             sscanf(scb->buf,"HELO %31s %29s",scb->username,password);
  266. #ifdef DEBUG
  267.             if(Mailtrace >= 3) {
  268.                 tcmdprintf("POP2SERV(pop_sm): Processing USER %s PASS %s\n",scb->username,password);
  269.                 tcmdprintf("POP2SERV(pop_sm): Calling poplogin() for %s:%s:\n",scb->username,password);
  270.             }
  271. #endif /* DEBUG */
  272.  
  273.             if (!poplogin(scb->username,password)) {
  274.                 log(scb->socket,"POP2 access DENIED to %s",
  275.                         scb->username);
  276.                 state_error(scb,"Access DENIED!!");
  277.                 return;
  278.             }
  279.  
  280.             log(scb->socket,"POP2 access granted to %s",
  281.                     scb->username);
  282.             open_folder(scb);
  283.         } else if (strncmp(scb->buf,quit_cmd,strlen(quit_cmd)) == 0){
  284.             do_cleanup(scb);
  285.         } else
  286.             state_error(scb,"(AUTH) Expected HELO or QUIT command");
  287. #ifdef DEBUG
  288.         if(Mailtrace >= 3)
  289.             tcmdprintf("POP2SERV(pop_sm): Leaving case AUTH\n");
  290. #endif /* DEBUG */
  291.         break;
  292.  
  293.     case MBOX:
  294.         if (strncmp(scb->buf,read_cmd,strlen(read_cmd)) == 0)
  295.             read_message(scb);
  296.  
  297. #ifdef POP_FOLDERS
  298.         else if (strncmp(scb->buf,fold_cmd,strlen(fold_cmd)) == 0)
  299.             select_folder(scb);
  300.  
  301. #endif
  302.  
  303.         else if (strncmp(scb->buf,quit_cmd,strlen(quit_cmd)) == 0) {
  304.             do_cleanup(scb);
  305.         } else
  306.             state_error(scb,
  307. #ifdef POP_FOLDERS
  308.                     "(MBOX) Expected FOLD, READ, or QUIT command");
  309. #else
  310.                     "(MBOX) Expected READ or QUIT command");
  311. #endif
  312.         break;
  313.  
  314.     case ITEM:
  315.         if (strncmp(scb->buf,read_cmd,strlen(read_cmd)) == 0)
  316.             read_message(scb);
  317.  
  318. #ifdef POP_FOLDERS
  319.  
  320.         else if (strncmp(scb->buf,fold_cmd,strlen(fold_cmd)) == 0)
  321.             select_folder(scb);
  322. #endif
  323.  
  324.         else if (strncmp(scb->buf,retr_cmd,strlen(retr_cmd)) == 0)
  325.             retrieve_message(scb);
  326.         else if (strncmp(scb->buf,quit_cmd,strlen(quit_cmd)) == 0)
  327.             do_cleanup(scb);
  328.         else
  329.             state_error(scb,
  330. #ifdef POP_FOLDERS
  331.                "(ITEM) Expected FOLD, READ, RETR, or QUIT command");
  332. #else
  333.                "(ITEM) Expected READ, RETR, or QUIT command");
  334. #endif
  335.         break;
  336.  
  337.     case NEXT:
  338.         if (strncmp(scb->buf,ackd_cmd,strlen(ackd_cmd)) == 0){
  339.                 /* ACKD processing */
  340.             deletemsg(scb,scb->msg_num);
  341.             scb->msg_num++;
  342.             get_message(scb,scb->msg_num);
  343.         } else if (strncmp(scb->buf,acks_cmd,strlen(acks_cmd)) == 0){
  344.                 /* ACKS processing */
  345.             scb->msg_num++;
  346.             get_message(scb,scb->msg_num);
  347.         } else if (strncmp(scb->buf,nack_cmd,strlen(nack_cmd)) == 0){
  348.                 /* NACK processing */
  349.             fseek(scb->wf,scb->curpos,SEEK_SET);
  350.         } else {
  351.             state_error(scb,"(NEXT) Expected ACKD, ACKS, or NACK command");
  352.             return;
  353.         }
  354.  
  355.         print_message_length(scb);
  356.         scb->state  = ITEM;
  357.         break;
  358.  
  359.     case DONE:
  360.         do_cleanup(scb);
  361.         break;
  362.  
  363.     default:
  364.         state_error(scb,"(TOP) State Error!!");
  365.         break;
  366.     }
  367.  
  368. #ifdef DEBUG
  369.     if(Mailtrace >= 3)
  370.         tcmdprintf("POP2SERV(pop_sm): Leaving state machine; state %u\n",scb->state);
  371. #endif /* DEBUG */
  372. }
  373.  
  374.  
  375.  
  376. static void
  377. do_cleanup (struct pop_scb *scb)
  378. {
  379.     void close_folder (struct pop_scb *);
  380.  
  381.     close_folder(scb);
  382.     (void) usputs(scb->socket,signoff_msg);
  383.     scb->state = DONE;
  384. }
  385.  
  386.  
  387.  
  388. static void
  389. state_error (struct pop_scb *scb, const char *msg)
  390. {
  391.     if(Mailtrace >= 2)
  392.         tcmdprintf(error_rsp,msg);
  393.     usprintf(scb->socket,error_rsp,msg);
  394.     scb->state = DONE;
  395. }
  396.  
  397.  
  398.  
  399. #ifdef POP_FOLDERS
  400.  
  401. static void
  402. select_folder(scb)
  403. struct pop_scb    *scb;
  404. {
  405.     sscanf(scb->buf,"FOLD %s",scb->username);
  406.  
  407.     if (scb->wf != NULL)
  408.         close_folder(scb);
  409.  
  410.     open_folder(scb);
  411. }
  412.  
  413. #endif
  414.  
  415.  
  416.  
  417. static void
  418. close_folder (struct pop_scb *scb)
  419. {
  420. char folder_pathname[128];
  421. char line[TLINELEN+1];
  422. FILE *fd;
  423. int deleted = FALSE;
  424. int msg_no = 0;
  425. struct stat folder_stat;
  426. int newmail (struct pop_scb *);
  427. int isdeleted (struct pop_scb *,int);
  428. char *cp;
  429. int firstIDline = 0, nextisBID = 0, k;
  430. int public, lines = 0;
  431. long last;
  432. struct let lt;
  433.  
  434.     if (scb->wf == NULL)
  435.         return;
  436.  
  437.     if (!scb->folder_modified) {
  438.         /* no need to re-write the folder if we have not modified it */
  439.  
  440.         fclose(scb->wf);
  441.         scb->wf = NULL;
  442.  
  443.         free((char *)scb->msg_status);
  444.         scb->msg_status = NULL;
  445.         return;
  446.     }
  447.  
  448.  
  449.     sprintf(folder_pathname,"%s/%s.txt",Mailspool,scb->username);
  450.  
  451.     if (newmail(scb)) {
  452.         /* copy new mail into the work file and save the
  453.            message count for later */
  454.  
  455.         if ((fd = fopen(folder_pathname,"r")) == NULL) {
  456.             state_error(scb,"Unable to add new mail to folder");
  457.             return;
  458.         }
  459.  
  460.         fseek(scb->wf,0,SEEK_END);
  461.         fseek(fd,scb->folder_file_size,SEEK_SET);
  462.         while (!feof(fd)) {
  463.             fgets(line,TLINELEN,fd);
  464.             fputs(line,scb->wf);
  465.         }
  466.  
  467.         fclose(fd);
  468.     }
  469.  
  470.     /* now create the updated mail folder */
  471.  
  472.     if ((fd = fopen(folder_pathname,"w")) == NULL){
  473.         state_error(scb,"Unable to update mail folder");
  474.         return;
  475.     }
  476.  
  477.     rewind(scb->wf);
  478.  
  479.     sprintf(line,"%s/control/%s.ctl",Mailspool,scb->username);
  480.     remove (line);
  481.     lt.start = last = 0;
  482.  
  483.     while (!feof(scb->wf)){
  484.         fgets(line,TLINELEN,scb->wf);
  485.         if (feof(scb->wf))
  486.             continue;
  487.         kwait(NULL);    /* give other processes time in long copy */
  488.  
  489.         if (isSOM(line)){
  490.             lt.size = last - lt.start - lines; 
  491.             if (lt.size && (deleted == FALSE))
  492.                 updateCtl (scb->username, <);
  493.             lines = lt.status = 0;
  494.             lt.start = last;
  495.             firstIDline = 0;
  496.  
  497.             msg_no++;
  498.             if (msg_no <= scb->folder_len)
  499.                 deleted = isdeleted(scb,msg_no);
  500.             else
  501.                 deleted = FALSE;
  502.         }
  503.  
  504.  
  505.         lines++;
  506.         if (!firstIDline && nextisBID && (cp=strstr(line,"AA")) != NULLCHAR) {
  507.             /*what follows is the message-number*/
  508.             lt.bid = atol(cp+2);
  509.             nextisBID = 0;
  510.             firstIDline = 1;
  511.             }
  512.  
  513.         if (!strncmp ("Received: ", line, 10))
  514.             nextisBID = 1;
  515.         if (!strncmp ("Status: R", line, 9))
  516.             lt.status = BM_READ;
  517.  
  518.         if (deleted)
  519.             continue;
  520.  
  521.         fputs(line,fd);
  522.         last = ftell (fd);
  523.     }
  524.  
  525.     lt.size = last - lt.start - lines; 
  526.     if (deleted == FALSE)
  527.         updateCtl (scb->username, <);
  528.  
  529.     fclose(fd);
  530.  
  531.     /* trash the updated mail folder if it is empty */
  532.  
  533. /*    if ((stat(folder_pathname,&folder_stat) == 0) && (folder_stat.st_size == 0)) */
  534.     if(fsize(folder_pathname) == 0L)        /* N1BEE */
  535.         unlink(folder_pathname);
  536.  
  537.     fclose(scb->wf);
  538.     scb->wf = NULL;
  539.  
  540.     free((char *)scb->msg_status);
  541.     scb->msg_status = NULL;
  542. }
  543.  
  544.  
  545.  
  546. static void
  547. open_folder (struct pop_scb *scb)
  548. {
  549. char folder_pathname[64];
  550. char line[TLINELEN+1];
  551. FILE *fd;
  552. struct stat folder_stat;
  553.  
  554.  
  555.     sprintf(folder_pathname,"%.45s/%.8s.txt",Mailspool,scb->username);
  556. #ifdef DEBUG
  557.     if(Mailtrace >= 3) {
  558.         tcmdprintf("POP2SERV(open_folder): will open %s\n",folder_pathname);
  559.     }
  560. #endif /* DEBUG */
  561.     scb->folder_len       = 0;
  562.     scb->folder_file_size = 0;
  563.  
  564.     /* Ordinarily, we would call stat() to find out if the file exists
  565.        and get its size at the same time.  However, there is a bug in
  566.        Borland's stat() code which crashes DesqView and OS/2 (!) if
  567.        stat() is called on a file which does not exist.  -- N1BEE
  568.     */
  569.  
  570.     /* if (stat(folder_pathname,&folder_stat)){ */
  571.     if((folder_stat.st_size = fsize(folder_pathname)) == -1L) { /* N1BEE */
  572. #ifdef DEBUG
  573.         if(Mailtrace >= 3) {
  574.             tcmdprintf("POP2SERV(open_folder): folder not found (empty)\n");
  575.         }
  576. #endif /* DEBUG */
  577.         (void) usputs(scb->socket,no_mail_rsp);
  578.  
  579.         /* state remains AUTH, expecting HELO or QUIT */
  580.         return;
  581.     }
  582.  
  583.     scb->folder_file_size = folder_stat.st_size;
  584.     if ((fd = fopen(folder_pathname,"r")) == NULL){
  585.         state_error(scb,"POP2SERV(open_folder): Unable to open mail folder");
  586.         return;
  587.     }
  588.  
  589.     if ((scb->wf = tmpfile()) == NULL) {
  590.         state_error(scb,"POP2SERV(open_folder): Unable to create work folder");
  591.         return;
  592.     }
  593.  
  594.     while(!feof(fd)) {
  595.         fgets(line,TLINELEN,fd);
  596.  
  597.         /* scan for begining of a message */
  598.  
  599.         if (isSOM(line))
  600.             scb->folder_len++;
  601.  
  602.         /* now put  the line in the work file */
  603.  
  604.         fputs(line,scb->wf);
  605.     }
  606.  
  607.     fclose(fd);
  608.  
  609.     scb->msg_status_size = (scb->folder_len) / BITS_PER_WORD;
  610.  
  611.     if ((((scb->folder_len) % BITS_PER_WORD) != 0) ||
  612.         (scb->msg_status_size == 0))
  613.         scb->msg_status_size++;
  614.  
  615.     if ((scb->msg_status = (int16 *) callocw(scb->msg_status_size,
  616.                 sizeof(int16))) == NULL) {
  617.         state_error(scb,"Unable to create message status array");
  618.         return;
  619.     }
  620.  
  621.     usprintf(scb->socket,count_rsp,scb->folder_len);
  622.  
  623.     scb->state  = MBOX;
  624.  
  625. #ifdef DEBUG
  626.     if(Mailtrace >= 3)
  627.         tcmdprintf("POP2SERV: open_folder() completed successfully.\n");
  628. #endif /* DEBUG */
  629. }
  630.  
  631.  
  632.  
  633. static void
  634. read_message (struct pop_scb *scb)
  635. {
  636.     void get_message (struct pop_scb *,int);
  637.     void print_message_length (struct pop_scb *);
  638.  
  639.     if (scb == NULLSCB)    /* check for null -- wa6smn */
  640.         return;
  641.     if (scb->buf[sizeof(read_cmd) - 1] == ' ')
  642.         scb->msg_num = atoi(&(scb->buf[sizeof(read_cmd) - 1]));
  643.     else
  644.         scb->msg_num++;
  645.  
  646.     get_message(scb,scb->msg_num);
  647.     print_message_length(scb);
  648.     scb->state  = ITEM;
  649. }
  650.  
  651.  
  652.  
  653. static void
  654. retrieve_message (struct pop_scb *scb)
  655. {
  656. char line[TLINELEN+1];
  657. long cnt;
  658.  
  659.     if (scb == NULLSCB)    /* check for null -- wa6smn */
  660.         return;
  661.     if (scb->msg_len == 0) {
  662.         state_error(scb,"Attempt to access a DELETED message!");
  663.         return;
  664.     }
  665.  
  666.     cnt  = scb->msg_len;
  667.     while(!feof(scb->wf) && (cnt > 0)) {
  668.         fgets(line,TLINELEN,scb->wf);
  669.         rip(line);
  670.  
  671.         usprintf(scb->socket,msg_line,line);
  672.         cnt -= (strlen(line)+2);    /* Compensate for CRLF */
  673.     }
  674.  
  675.     scb->state = NEXT;
  676. }
  677.  
  678.  
  679.  
  680. static void
  681. get_message (struct pop_scb *scb, int msg_no)
  682. {
  683. char line[TLINELEN+1];
  684. long ftell (FILE *);
  685. int isdeleted (struct pop_scb *, int);
  686.  
  687.     if (scb == NULLSCB)    /* check for null -- wa6smn */
  688.         return;
  689.     scb->msg_len = 0;
  690.     if (msg_no > scb->folder_len) {
  691.         scb->curpos  = 0;
  692.         scb->nextpos = 0;
  693.         return;
  694.     } else {
  695.         /* find the message and its length */
  696.  
  697.         rewind(scb->wf);
  698.         while (!feof(scb->wf) && (msg_no > -1)) {
  699.             if (msg_no > 0)
  700.                 scb->curpos = ftell(scb->wf);
  701.                 
  702.             fgets(line,TLINELEN,scb->wf);
  703.             rip(line);
  704.  
  705.             if (isSOM(line))
  706.                 msg_no--;
  707.  
  708.             if (msg_no != 0)
  709.                 continue;
  710.  
  711.             scb->nextpos  = ftell(scb->wf);
  712.             scb->msg_len += (strlen(line)+2);    /* Add CRLF */
  713.         }
  714.     }
  715.  
  716.     if (scb->msg_len > 0)
  717.         fseek(scb->wf,scb->curpos,SEEK_SET);
  718.  
  719.     /* we need the pointers even if the message was deleted */
  720.  
  721.     if  (isdeleted(scb,scb->msg_num))
  722.         scb->msg_len = 0;
  723. }
  724.  
  725.  
  726.  
  727. static int
  728. poplogin(username,pass)
  729. char *pass;
  730. char *username;
  731. {
  732. char buf[80];
  733. char *cp;
  734. char *cp1;
  735. FILE *fp;
  736.  
  737. #ifdef DEBUG
  738.     if(Mailtrace >= 3)
  739.         tcmdprintf("POP2SERV(poplogin): Opening POP users file %s\n",Popusers);
  740. #endif /* DEBUG */
  741.  
  742.     if((fp = fopen(Popusers,"r")) == NULLFILE) {
  743.         /* User file doesn't exist */
  744.         tprintf("POP2 users file %s not found\n",Popusers);
  745.         return(FALSE);
  746.     }
  747.  
  748. #ifdef DEBUG
  749.     if(Mailtrace >= 3)
  750.         tcmdprintf("POP2SERV(poplogin): Login request from %s:%s:\n",username,pass);
  751. #endif /* DEBUG */
  752.  
  753.     while(fgets(buf,sizeof(buf),fp),!feof(fp)) {
  754.         if(buf[0] == '#')
  755.             continue;    /* Comment */
  756.  
  757.         if((cp = strchr(buf,':')) == NULLCHAR)
  758.             /* Bogus entry */
  759.             continue;
  760.  
  761.         *cp++ = '\0';        /* Now points to password */
  762.         if(strcmp(username,buf) == 0)
  763.             break;        /* Found user name */
  764.     }
  765.  
  766.     if(feof(fp)) {
  767. #ifdef DEBUG
  768.         if(Mailtrace >= 3)
  769.             tcmdprintf("POP2SERV(poplogin): username not found in POPUSERS\n");
  770. #endif /* DEBUG */
  771.         /* User name not found in file */
  772.  
  773.         fclose(fp);
  774.         return(FALSE);
  775.     }
  776.     fclose(fp);
  777.  
  778.     if ((cp1 = strchr(cp,':')) == NULLCHAR) {
  779. #ifdef DEBUG
  780.         if(Mailtrace >= 3)
  781.             tcmdprintf("POP2SERV(poplogin): No second ':' in POPUSERS entry\n");
  782. #endif /* DEBUG */
  783.         return(FALSE);
  784.     }
  785.  
  786.     *cp1 = '\0';
  787.     if(strcmp(cp,pass) != 0) {
  788. #ifdef DEBUG
  789.         if(Mailtrace >= 3)
  790.             tcmdprintf("POP2SERV(poplogin): Wrong password (%s) from user %s, expecting %s\n",pass,username,cp);
  791. #endif /* DEBUG */
  792.         /* Password required, but wrong one given */
  793.         return(FALSE);
  794.     }
  795.  
  796.     /* whew! finally made it!! */
  797. #ifdef DEBUG
  798.     if(Mailtrace >= 3)
  799.         tcmdprintf("POP2SERV(poplogin): %s authenticated\n",username);
  800. #endif /* DEBUG */
  801.  
  802.     return(TRUE);
  803. }
  804.  
  805.  
  806.  
  807. static int
  808. isdeleted (struct pop_scb *scb, int msg_no)
  809. {
  810. int16 mask = 1,offset;
  811.  
  812.     msg_no--;
  813.     offset = msg_no / BITS_PER_WORD;
  814.     mask <<= msg_no % BITS_PER_WORD;
  815.     return (((scb->msg_status[offset]) & mask)? TRUE:FALSE);
  816. }
  817.  
  818.  
  819.  
  820. static void
  821. deletemsg (struct pop_scb *scb, int msg_no)
  822. {
  823. int16 mask = 1,offset;
  824.  
  825.     if (scb == NULLSCB)    /* check for null -- wa6smn */
  826.         return;
  827.     msg_no--;
  828.     offset = msg_no / BITS_PER_WORD;
  829.     mask <<= msg_no % BITS_PER_WORD;
  830.     scb->msg_status[offset] |= mask;
  831.     scb->folder_modified = TRUE;
  832. }
  833.  
  834.  
  835.  
  836. static int
  837. newmail (struct pop_scb *scb)
  838. {
  839. char folder_pathname[64];
  840. struct stat folder_stat;
  841.  
  842.     sprintf(folder_pathname,"%s/%s.txt",Mailspool,scb->username);
  843.  
  844.     /* if (stat(folder_pathname,&folder_stat)) { */
  845.     if((folder_stat.st_size = fsize(folder_pathname)) == -1L) { /* N1BEE */
  846.         state_error(scb,"Unable to get old mail folder's status");
  847.         return(FALSE);
  848.     } else
  849.         return ((folder_stat.st_size > scb->folder_file_size)? TRUE:FALSE);
  850. }
  851.  
  852.  
  853.  
  854. static void
  855. print_message_length (struct pop_scb *scb)
  856. {
  857. char *print_control_string;
  858.  
  859.     if (scb == NULLSCB)    /* check for null -- wa6smn */
  860.         return;
  861.     if (scb->msg_len > 0)
  862.         print_control_string = length_rsp;
  863.     else if (scb->msg_num <= scb->folder_len)
  864.         print_control_string = length_rsp;
  865.     else
  866.         print_control_string = no_more_rsp;
  867.  
  868.     (void)usprintf(scb->socket,print_control_string,scb->msg_len,scb->msg_num);
  869. }
  870.  
  871. #endif
  872.